package com.nami.gate.network;

import com.nami.gate.config.GateConfig;
import com.nami.gate.network.factory.NettyEventLoopFactory;
import com.nami.gate.network.initializer.WsServerInitializer;
import com.nami.gate.process.upmsg.PackageProcessFactory;
import com.nami.gate.middleware.mq.MqSender;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.nami.gate.constants.NettyConstants.*;

public class NettyServerImpl implements NetworkService {

    private static final Logger log = LoggerFactory.getLogger(NettyServerImpl.class);

    protected EventLoopGroup bossGroup;

    protected EventLoopGroup workGroup;

    protected ServerBootstrap serverBootstrap = new ServerBootstrap();

    protected Channel channel;


    // -----------------------------------------------------------------------

    protected GateConfig gateConfig;

    protected MqSender sender;

    protected PackageProcessFactory processFactory;

    public NettyServerImpl(GateConfig config,
                           MqSender sender,
                           PackageProcessFactory processFactory) {
        this.gateConfig = config;
        this.sender = sender;
        this.processFactory = processFactory;
    }

    @Override
    public void start() throws Exception {
        // 启动netty
        this.bossGroup = newBossWorkerGroup();
        this.workGroup = newWorkerGroup();

        this.serverBootstrap
            .group(bossGroup, workGroup)
            .channel(NettyEventLoopFactory.createServerSocketChannelClass())
            // 服务端可连接的最大队列数量
            .option(ChannelOption.SO_BACKLOG, 10240)
            // TODO 注意此处，消息接收有延迟，发送慢，记得查看此处相关配置
//            .option(ChannelOption.SO_RCVBUF, 1024 * 1024)  // 设置接收缓冲区为1MB
//            .option(ChannelOption.SO_SNDBUF, 1024 * 1024)  // 设置发送缓冲区为1MB
            // 允许重复使用本地地址和端口
            .option(ChannelOption.SO_REUSEADDR, true)
            // 子线程组禁用 Nagle 算法，简单点说是否批量发送数据 true关闭 false开启。 开启的话可以减少一定的网络开销，但影响消息实时性
            .childOption(ChannelOption.TCP_NODELAY, true)
            // 保活机制，2h 没数据会发送心跳包检测
            .childOption(ChannelOption.SO_KEEPALIVE, true)
            .childHandler(new WsServerInitializer(gateConfig, sender, processFactory));

        ChannelFuture channelFuture = this.serverBootstrap
            .bind(gateConfig.getGatePort())
            .addListener(future -> {
                if (future.isSuccess()) {
                    log.info("netty [{}] server in {} port start finish....", getClass().getSimpleName(), gateConfig.getGatePort());
                } else {
                    log.error("server start failure on:{}", gateConfig.getGatePort(), future.cause());
                }
            });
        this.channel = channelFuture.channel();
    }

    private EventLoopGroup newBossWorkerGroup() {
        return NettyEventLoopFactory.createEventLoopGroup(1, NETTY_BOSS_GROUP_THREAD_NAME_PREFIX);
    }

    protected EventLoopGroup newWorkerGroup() {
        return NettyEventLoopFactory.createEventLoopGroup(DEFAULT_IO_THREADS, NETTY_WORK_GROUP_THREAD_NAME_PREFIX);
    }

    @Override
    public void shutdown() {
        if (channel != null) {
            channel.close();
        }
        bossGroup.shutdownGracefully();
        workGroup.shutdownGracefully();
    }

}
